﻿using Lidgren.Network;
using System;
using System.ComponentModel;
using System.Text;
using System.Threading;

namespace Lidgren.Server
{
	class Program
	{
		private static bool _isRunning = true;
		private static BackgroundWorker _listener;
		private static NetServer _server;
		private static StringBuilder _outputBuffer;

		static void Main(string[] args)
		{
			var config = new NetPeerConfiguration("chat") //"lidgren-Server")
			{
				MaximumConnections = 100,
				Port = 28657 // lowest fibonacci prime
			};

			_server = new NetServer(config);
			_outputBuffer = new StringBuilder();

			_listener = new BackgroundWorker
			{
				WorkerReportsProgress = true
			};
			_listener.DoWork += DoWork;
			_listener.ProgressChanged += ReportProgress;
			_listener.RunWorkerAsync();

			_server.Start();

			Console.WriteLine("Server started...");
			while (_isRunning)
			{
				var input = Console.ReadLine();
				input = input.ToLower();

				if (input == "exit" || input == "shutdown")
				{
					Console.WriteLine("Shutting down...");
					_isRunning = false;
				}
				else if (input.StartsWith("send"))
				{
					var split = input.Split(' ');
					var msg = _server.CreateMessage(split[1]);
					var all = _server.Connections;
					_server.SendMessage(msg, all, NetDeliveryMethod.ReliableOrdered, 0);
				}
				else
				{
					Console.WriteLine("Unknown command: {0}", input);
				}
			}

			_server.Shutdown("Shutting down");
		}

		private static void ReportProgress(object sender, ProgressChangedEventArgs progressChangedEventArgs)
		{
			Console.WriteLine(_outputBuffer.ToString());
			_outputBuffer.Clear();
		}

		private static void DoWork(object sender, DoWorkEventArgs e)
		{
			NetIncomingMessage msg;
			while (_isRunning)
			{
				while ((msg = _server.ReadMessage()) != null)
				{
					switch (msg.MessageType)
					{
						case NetIncomingMessageType.DebugMessage:
						case NetIncomingMessageType.ErrorMessage:
						case NetIncomingMessageType.WarningMessage:
						case NetIncomingMessageType.VerboseDebugMessage:
							var text = msg.ReadString();
							_outputBuffer.Append(text + "\r\n");
							break;
						case NetIncomingMessageType.StatusChanged:
							var status = (NetConnectionStatus) msg.ReadByte();
							var reason = msg.ReadString();
							_outputBuffer.Append(NetUtility.ToHexString(msg.SenderConnection.RemoteUniqueIdentifier) + " " + status + ": " +
							                     reason);
							if (status == NetConnectionStatus.Connected)
							{
								_outputBuffer.Append("Remote hail: " + msg.SenderConnection.RemoteHailMessage.ReadString());
							}
							// UpdateConnectionsList();
							break;
						case NetIncomingMessageType.Data:
							var chat = msg.ReadString();
							_outputBuffer.Append(chat);
							var all = _server.Connections;
							all.Remove(msg.SenderConnection);

							if (all.Count > 0)
							{
								var oMsg = _server.CreateMessage();
								oMsg.Write(NetUtility.ToHexString(msg.SenderConnection.RemoteUniqueIdentifier) + " said " + chat);
								_server.SendMessage(oMsg, all, NetDeliveryMethod.ReliableOrdered, 0);
							}
							break;
						default:
							_outputBuffer.Append("Unhandled type: " + msg.MessageType + " " + msg.LengthBytes + " bytes " + msg.DeliveryMethod + "|" + msg.SequenceChannel);
							break;
					}
					_server.Recycle(msg);
					_listener.ReportProgress(0);
					Thread.Sleep(1);
				}
			}
		}
	}
}